/** * This file is part of Waarp Project. * * Copyright 2009, Frederic Bregier, and individual contributors by the @author tags. See the * COPYRIGHT.txt in the distribution for a full listing of individual contributors. * * All Waarp Project is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License along with Waarp . If not, see * <http://www.gnu.org/licenses/>. */ package org.waarp.xample; /* * Copyright (c) 2003 Felix Golubov */ import java.awt.*; import java.awt.event.*; import java.util.*; import java.util.List; import java.io.*; import java.net.*; import javax.swing.*; import org.w3c.dom.*; import org.waarp.xample.custnodes.*; import org.apache.xml.serialize.OutputFormat; import org.apache.xml.serialize.XMLSerializer; import com.fg.util.FLoader; import com.fg.util.FadingFilter; import com.fg.xmleditor.*; /** * A simple application demonstrates usage of the Swing-based XML editing component * {@link com.fg.xmleditor.FXDoubleView}. The component generates document-specific GUI for each * particular type of the XML document, specified by the XML Schema. A User-Manual document, which * is included into XAmple XML Editor distribution package, provides detailed description of how to * customize XML Schema documents with the editor-specific features, such as custom field editors, * additional labeling, node-specific messages, etc. * <p> * </p> * The application creares an instance of the {@link org.waarp.xample.custnodes.FFileDialog} and * registers it with the {@link com.fg.xmleditor.FXDoubleView} under "FileDialog" id, so it can be * used as a global field editor. (Actually there is no particular sense in doing it since the * dialog is not initialized with any specific data. It is just an example). * * @author Felix Golubov * @author frederic bregier * @version 2.0 */ public class XAmple extends JFrame implements ActionListener, ItemListener, FXModelStatusListener { public static String FILE_GUI = "gui.properties"; public static String FONT_NAME = "FONT_NAME"; public static String FONT_SIZE = "FONT_SIZE"; public static String FILE_RUNTIME = "runtime.properties"; public static String LOOK_AND_FEEL = "LOOK_AND_FEEL"; public static String BOUNDS_LEFT = "BOUNDS_LEFT"; public static String BOUNDS_TOP = "BOUNDS_TOP"; public static String BOUNDS_WIDTH = "BOUNDS_WIDTH"; public static String BOUNDS_HEIGHT = "BOUNDS_HEIGHT"; History history = new History(""); FHistoryButton btnOpenXSD; FHistoryButton btnOpenXML; JButton btnNewXML; JButton btnSaveXML; JToggleButton btnHorizSplit; JToggleButton btnVertSplit; ButtonGroup splitGroup = new ButtonGroup(); JToggleButton btnSync; JMenuBar menuBar = new JMenuBar(); JMenu menuFile = new JMenu("File"); JMenuItem mOpenXSD = new JMenuItem("Open XML Configuration Schema"); JMenuItem mOpenXML = new JMenuItem("Open XML Configuration Document"); JMenuItem mNewXML = new JMenuItem("New XML Configuration Document"); JMenuItem mSaveXML = new JMenuItem("Save XML Configuration Document"); JMenuItem mExit = new JMenuItem("Exit"); JMenu menuLF = new JMenu("Look & Feel"); JMenu menuHelp = new JMenu("Help"); JMenuItem mAbout = new JMenuItem("About..."); FXDoubleView dblView; FXDocumentModel model; JFileChooser fileDlg; TheFileFilter xsdFilter = new TheFileFilter("xsd", "XML Schema files *.xsd"); TheFileFilter xmlFilter = new TheFileFilter("xml", "XML files *.xml"); FFileDialog fFileDialog = new FFileDialog(); String xsdFileName = ""; String xmlFileName = ""; class TheFileFilter extends javax.swing.filechooser.FileFilter { String extension; String description; public TheFileFilter(String extension, String description) { this.extension = extension; this.description = description; } public boolean accept(File f) { if (f.isDirectory()) return true; String ext = null; String name = f.getName(); int i = name.lastIndexOf('.'); if (i > 0 && i < name.length() - 1) ext = name.substring(i + 1).toLowerCase(); else ext = ""; return ext.equals(extension); } public String getDescription() { return description; } } class Btn extends JButton { public Btn(ImageIcon icon, String toolTipText) { super(icon); setFocusPainted(false); setDisabledIcon(FadingFilter.fade(icon)); setToolTipText(toolTipText); setEnabled(false); setPreferredSize(new Dimension(35, 27)); setMinimumSize(new Dimension(35, 27)); setMaximumSize(new Dimension(35, 27)); addActionListener(XAmple.this); } } class ToggleBtn extends JToggleButton { public ToggleBtn(ImageIcon icon, String toolTipText) { super(icon); setFocusPainted(false); setDisabledIcon(FadingFilter.fade(icon)); setToolTipText(toolTipText); setPreferredSize(new Dimension(35, 27)); setMinimumSize(new Dimension(35, 27)); setMaximumSize(new Dimension(35, 27)); addActionListener(XAmple.this); } } public XAmple() { HistoryIO.load(history); this.setTitle("XAmple-Waarp"); this.getContentPane().setLayout(new BorderLayout()); ImageIcon icoOpenXSD = FLoader.getIcon(this, "OpenXSD.gif"); ImageIcon icoOpenXML = FLoader.getIcon(this, "OpenXML.gif"); ImageIcon icoNewXML = FLoader.getIcon(this, "NewXML.gif"); ImageIcon icoSaveXML = FLoader.getIcon(this, "SaveXML.gif"); ImageIcon imgHorizSplit = FLoader.getIcon(this, "HorizSplit.gif"); ImageIcon imgVertSplit = FLoader.getIcon(this, "VertSplit.gif"); ImageIcon imgSync = FLoader.getIcon(this, "Sync.gif"); JToolBar toolBar = new JToolBar(); btnOpenXSD = new FHistoryButton(icoOpenXSD, "Open XML Configuration Schema", "Reopen XML Configuration Schema"); btnOpenXSD.addActionListener(this); btnOpenXSD.addItemListener(this); btnOpenXSD.setItems(history.items); toolBar.add(btnOpenXSD); toolBar.addSeparator(new Dimension(2, 1)); btnOpenXML = new FHistoryButton(icoOpenXML, "Open XML Configuration Document", "Reopen XML Configuration Document"); btnOpenXML.setEnabled(false); btnOpenXML.addActionListener(this); btnOpenXML.addItemListener(this); toolBar.add(btnOpenXML); toolBar.addSeparator(); btnNewXML = new Btn(icoNewXML, "New XML Configuration Document"); toolBar.add(btnNewXML); btnSaveXML = new Btn(icoSaveXML, "Save XML Configuration Document"); toolBar.add(btnSaveXML); toolBar.addSeparator(); btnHorizSplit = new ToggleBtn(imgHorizSplit, "Horizontal Split"); splitGroup.add(btnHorizSplit); toolBar.add(btnHorizSplit); btnVertSplit = new ToggleBtn(imgVertSplit, "Vertical Split"); splitGroup.add(btnVertSplit); toolBar.add(btnVertSplit); toolBar.addSeparator(); btnSync = new ToggleBtn(imgSync, "Synchronized Node Selection"); toolBar.add(btnSync); mOpenXSD.addActionListener(this); menuFile.add(mOpenXSD); mOpenXML.setEnabled(false); mOpenXML.addActionListener(this); menuFile.add(mOpenXML); mNewXML.setEnabled(false); mNewXML.addActionListener(this); menuFile.add(mNewXML); menuFile.addSeparator(); mSaveXML.setEnabled(false); mSaveXML.addActionListener(this); menuFile.add(mSaveXML); menuFile.addSeparator(); mExit.addActionListener(this); menuFile.add(mExit); UIManager.LookAndFeelInfo[] lfi = UIManager.getInstalledLookAndFeels(); LookAndFeel lf = UIManager.getLookAndFeel(); ButtonGroup group = new ButtonGroup(); for (int i = 0; i < lfi.length; i++) { JRadioButtonMenuItem mi = new JRadioButtonMenuItem(lfi[i].getName()); group.add(mi); if (lfi[i].getClassName().equals(lf.getClass().getName())) mi.setSelected(true); mi.addActionListener(this); menuLF.add(mi); } mAbout.addActionListener(this); menuHelp.add(mAbout); menuBar.add(menuFile); menuBar.add(menuLF); menuBar.add(menuHelp); this.setJMenuBar(menuBar); this.getContentPane().add(toolBar, BorderLayout.NORTH); model = new FXDocumentModelImpl(); model.addModelStatusListener(this); dblView = new FXDoubleView(model); dblView.addExternalDialog("FileDialog", fFileDialog); this.getContentPane().add(dblView, BorderLayout.CENTER); fileDlg = new JFileChooser(new File(".").getAbsolutePath()); fileDlg.addChoosableFileFilter(xsdFilter); fileDlg.addChoosableFileFilter(xmlFilter); } void showXSDTitle() { setTitle("XAmple-GG - " + xsdFileName + " : <noname>.xml"); } void showXMLTitle() { setTitle("XAmple-GG - " + xsdFileName + " : " + xmlFileName); } void saveRuntimeProperties() { Properties props = new Properties(); LookAndFeel lf = UIManager.getLookAndFeel(); if (lf != null) props.setProperty(LOOK_AND_FEEL, lf.getName()); Rectangle r = getBounds(); props.setProperty(BOUNDS_LEFT, "" + r.x); props.setProperty(BOUNDS_TOP, "" + r.y); props.setProperty(BOUNDS_WIDTH, "" + r.width); props.setProperty(BOUNDS_HEIGHT, "" + r.height); OutputStream out = null; try { File file = new File(FILE_RUNTIME); file.createNewFile(); out = new FileOutputStream(file); props.store(out, "XAmple-Waarp XML Editor runtime properties"); } catch (Exception ex) { ex.printStackTrace(); } finally { try { out.close(); } catch (Exception ignore) { } } HistoryIO.save(history); } protected void processWindowEvent(WindowEvent e) { if (e.getID() == WindowEvent.WINDOW_CLOSING) { if (confirmation()) { saveRuntimeProperties(); System.exit(0); } } } public void itemStateChanged(ItemEvent e) { if (!confirmation()) return; ItemSelectable source = e.getItemSelectable(); String path = ((History) e.getItem()).path; File file = new File(path); if (source == btnOpenXSD) loadXMLSchema(file); else if (source == btnOpenXML) loadXMLDocument(file); fileDlg.setCurrentDirectory(file.getParentFile()); } public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == btnOpenXSD || source == mOpenXSD) openXSD(); else if (source == btnOpenXML || source == mOpenXML) openXML(); else if (source == btnNewXML || source == mNewXML) newXML(); else if (source == btnSaveXML || source == mSaveXML) saveXML(); else if (source == btnHorizSplit) dblView.setOrientation(JSplitPane.HORIZONTAL_SPLIT); else if (source == btnVertSplit) dblView.setOrientation(JSplitPane.VERTICAL_SPLIT); else if (source == btnSync) dblView.setSyncSelectNodes(btnSync.getModel().isSelected()); else if (source instanceof JRadioButtonMenuItem) updateLookAndFeel(((JRadioButtonMenuItem) source).getText()); else if (source == mAbout) showDlgAbout(); else if (source == mExit) exit(); } void updateLookAndFeel(String lfName) { LookAndFeel lf = UIManager.getLookAndFeel(); if (lf != null && lf.getName().equals(lfName)) return; UIManager.LookAndFeelInfo[] lfi = UIManager.getInstalledLookAndFeels(); for (int i = 0; i < lfi.length; i++) { if (lfi[i].getName().equals(lfName)) { try { // dblView.stopEditing(); UIManager.setLookAndFeel(lfi[i].getClassName()); SwingUtilities.updateComponentTreeUI(this); javax.swing.filechooser.FileFilter currFilter = fileDlg.getFileFilter(); fileDlg.setAcceptAllFileFilterUsed(fileDlg.getAcceptAllFileFilter() == null); SwingUtilities.updateComponentTreeUI(fileDlg); fileDlg.setAcceptAllFileFilterUsed(true); fileDlg.setFileFilter(currFilter); SwingUtilities.updateComponentTreeUI(fFileDialog); return; } catch (Exception ignore) { } } } } void showDlgAbout() { DlgAbout dlg = new DlgAbout(this); Dimension dlgSize = dlg.getPreferredSize(); Dimension frmSize = getSize(); Point loc = getLocation(); dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x, (frmSize.height - dlgSize.height) / 2 + loc.y); dlg.setModal(true); dlg.setVisible(true); } boolean confirmation() { if (dblView.isDocChanged()) { int option = JOptionPane.showConfirmDialog(this, "The XML Configuration Document has been changed. Do you like to save it?", "information", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (option == JOptionPane.CANCEL_OPTION) return false; else if (option == JOptionPane.YES_OPTION) return saveXML(); else return true; } else return true; } void openXSD() { if (!confirmation()) return; fileDlg.setFileFilter(xsdFilter); if (fileDlg.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { File file = fileDlg.getSelectedFile(); if (file == null) return; loadXMLSchema(file); } } void openXML() { if (!confirmation()) return; fileDlg.setFileFilter(xmlFilter); if (fileDlg.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { File file = fileDlg.getSelectedFile(); if (file == null) return; loadXMLDocument(file); } } void newXML() { if (!confirmation()) return; try { if (model.getSchemaURL() == null) throw new FXModelException("No XML Configuration Schema loaded"); NewDocumentDialog dlg = new NewDocumentDialog(this, model); dlg.pack(); dlg.setLocationRelativeTo(dblView); dlg.setVisible(true); if (!dlg.isStatusOK()) return; model.newDocument(model.getSchemaURL(), dlg.getRootNamespace(), dlg.getRootElementName()); setXMLEnabled(true); } catch (Exception ex) { ex.printStackTrace(); setXMLEnabled(false); dblView.showErrorMessage("Error: " + ex.getMessage()); JOptionPane.showMessageDialog(this, "Can't open new XML Configuration Document", "Error", JOptionPane.ERROR_MESSAGE); } showXSDTitle(); } boolean saveXML() { Document doc = model.getDocument(); if (doc == null) return false; fileDlg.setFileFilter(xmlFilter); if (fileDlg.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { File file = fileDlg.getSelectedFile(); if (file == null) return false; if (file.getName().indexOf(".") < 0) file = new File(file.getAbsolutePath() + ".xml"); FileOutputStream out = null; Writer writer = null; try { file.createNewFile(); out = new FileOutputStream(file); OutputFormat format = new OutputFormat(doc, "UTF-8", true); writer = new OutputStreamWriter(out, "UTF-8"); XMLSerializer serial = new XMLSerializer(writer, format); serial.asDOMSerializer(); serial.serialize(doc); model.setDocumentChanged(false); xmlFileName = file.getName(); showXMLTitle(); History childHistory = history.getFirstChild(); if (childHistory != null) { childHistory.put(file.getAbsolutePath()); btnOpenXML.setItems(childHistory.items); } return true; } catch (Exception ex) { dblView.showErrorMessage("Error: " + ex.getMessage()); return false; } finally { try { out.close(); } catch (Exception ignore) { } try { writer.close(); } catch (Exception ignore) { } } } else return false; } void exit() { if (!confirmation()) return; saveRuntimeProperties(); System.exit(0); } void setSchemaEnabled(boolean enabled) { btnOpenXML.setEnabled(enabled); mOpenXML.setEnabled(enabled); btnNewXML.setEnabled(enabled); mNewXML.setEnabled(enabled); setXMLEnabled(enabled); } void setXMLEnabled(boolean enabled) { btnSaveXML.setEnabled(enabled); mSaveXML.setEnabled(enabled); } boolean loadXMLSchema(File file) { try { model.newDocument(file.toURI().toURL()); setSchemaEnabled(true); xsdFileName = file.getName(); showXSDTitle(); History childHistory = history.put(file.getAbsolutePath()); btnOpenXSD.setItems(history.items); btnOpenXML.setItems(childHistory.items); dblView.showInfoMessage("XML Configuration Schema: " + file.getAbsolutePath()); return true; } catch (Exception ex) { history.remove(file.getAbsolutePath()); btnOpenXSD.setItems(history.items); btnOpenXML.setItems(null); dblView.showErrorMessage("Error: " + ex.toString()); setSchemaEnabled(false); JOptionPane.showMessageDialog(this, "Can't load the XML Configuration Schema", "Error", JOptionPane.ERROR_MESSAGE); setTitle("XAmple"); return false; } } boolean loadXMLDocument(File file) { History childHistory = history.getFirstChild(); try { URL url = file.toURI().toURL(); List lostElements = model.openDocument(model.getSchemaURL(), url); if (lostElements != null) { StringBuffer sb = new StringBuffer( "Error: The source XML Configuration document is invalid.\n" + "The following elements have not been loaded:"); for (int i = 0; i < lostElements.size(); i++) { sb.append("\n"); int k = sb.length(); Node element = (Node) lostElements.get(i); sb.append(element.getNodeName()); Node node = element.getParentNode(); while (node != null && !(node instanceof Document)) { sb.insert(k, node.getNodeName() + "/"); node = node.getParentNode(); } } dblView.showErrorMessage(sb.toString()); } setXMLEnabled(true); xmlFileName = file.getName(); showXMLTitle(); childHistory.put(file.getAbsolutePath()); btnOpenXML.setItems(childHistory.items); dblView.showInfoMessage("XML Configuration Document: " + file.getAbsolutePath()); return true; } catch (Exception ex) { childHistory.remove(file.getAbsolutePath()); btnOpenXML.setItems(childHistory.items); // dblView.clear(); setXMLEnabled(false); dblView.showErrorMessage("Error: " + ex.getMessage()); JOptionPane.showMessageDialog(this, "Can't load the XML Configuration Document", "Error", JOptionPane.ERROR_MESSAGE); showXSDTitle(); return false; } } public void newDocumentLoaded(FXStatusEvent e) { } public void docValidityStatusChanged(FXStatusEvent e) { } static void assignDefaultFont() { Properties props = new Properties(); InputStream in = null; String fontName = null; int fontSize = 12; try { File file = new File(FILE_GUI); if (!file.exists()) return; in = new FileInputStream(file); props.load(in); fontName = props.getProperty(FONT_NAME); if (fontName == null || fontName.length() == 0) return; try { fontSize = Integer.parseInt(props.getProperty(FONT_SIZE, "12")); } catch (Exception ignore) { } } catch (Exception ex) { ex.printStackTrace(); return; } finally { try { in.close(); } catch (Exception ignore) { } } Font font = new Font(fontName, Font.PLAIN, fontSize); Enumeration keys = UIManager.getDefaults().keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); Object value = UIManager.get(key); if (value instanceof javax.swing.plaf.FontUIResource) UIManager.put(key, font); } } public static void main(String[] args) { assignDefaultFont(); Properties props = new Properties(); InputStream in = null; try { File file = new File(FILE_RUNTIME); if (file.exists()) { in = new FileInputStream(file); props.load(in); } String lfName = props.getProperty(LOOK_AND_FEEL); String lfClassName = null; UIManager.LookAndFeelInfo[] lfi = UIManager.getInstalledLookAndFeels(); for (int i = 0; i < lfi.length && lfClassName == null; i++) { if (lfi[i].getName().equals(lfName)) lfClassName = lfi[i].getClassName(); } if (lfClassName != null) UIManager.setLookAndFeel(lfClassName); else UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); } catch (Exception ex) { try { UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); } catch (Exception ex1) { ex1.printStackTrace(); } } finally { try { if (in != null) in.close(); } catch (Exception ignore) { } } XAmple frame = new XAmple(); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); try { Rectangle r = new Rectangle(); r.x = Integer.parseInt(props.getProperty(BOUNDS_LEFT)); r.y = Integer.parseInt(props.getProperty(BOUNDS_TOP)); r.width = Integer.parseInt(props.getProperty(BOUNDS_WIDTH)); r.height = Integer.parseInt(props.getProperty(BOUNDS_HEIGHT)); if (r.width > screenSize.width) r.width = screenSize.width; if (r.height > screenSize.height) r.height = screenSize.height; if (r.x + r.width > screenSize.width) r.x = screenSize.width - r.width; if (r.y + r.height > screenSize.height) r.y = screenSize.height - r.height; frame.setBounds(r.x, r.y, r.width, r.height); frame.validate(); } catch (Exception ex) { frame.pack(); Dimension d = frame.getSize(); if (d.height > screenSize.height) d.height = screenSize.height; if (d.width > screenSize.width) d.width = screenSize.width; frame.setLocation((screenSize.width - d.width) / 2, (screenSize.height - d.height) / 2); } frame.setVisible(true); } }